package com.stichedtogether.dao;


import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Set;

import javax.sql.DataSource;

import org.apache.commons.beanutils.PropertyUtils;

import com.stichedtogether.annotations.field.Primary;
import com.stichedtogether.annotations.type.Table;
import com.stichedtogether.test.DatabaseDriver;


public class QueryExecutor {

	DataSource datasource = DatabaseDriver.getDataSource();

	public <T> ArrayList<Object> Insert(Class<T> clazz, HashMap<String, Object> values) throws Exception{
		Table table = (Table) clazz.getAnnotation(Table.class);
		String flds ="(";
		String value = "(";
		for (String fld : values.keySet())
		{
			flds+=fld+", ";
			value+=parseType(values.get(fld))+", ";
		}
		flds = flds.substring(0, flds.length()-2) +") VALUES "+value.substring(0, value.length()-2)+")";
		Connection connection = datasource.getConnection();
		PreparedStatement ps = connection.prepareStatement("INSERT INTO "+table.name()+ flds, PreparedStatement.RETURN_GENERATED_KEYS);
		ps.executeUpdate();
		ResultSet rs = ps.getGeneratedKeys();
		if(!rs.next()) {
			closeConnection(connection, ps, rs);
			return null;
		}
		values = new HashMap<String, Object>();
		Field[] fields = clazz.getDeclaredFields();
		int column = 1;
		for(Field field : fields)
			if(field.isAnnotationPresent(Primary.class))
				values.put(field.getName(), rs.getObject(column++));
		closeConnection(connection, ps, rs);
		return Read(clazz, values);
	}

	private void closeConnection(Connection connection, PreparedStatement ps, ResultSet rs) throws SQLException {
		rs.close();
		ps.close();
		connection.close();
	}

	public <T> ArrayList<Object> Read(Class<T> clazz, HashMap<String, Object> values) throws Exception{
		Table table = (Table) clazz.getAnnotation(Table.class);
		Connection connection = datasource.getConnection();
		PreparedStatement ps = connection.prepareStatement("SELECT * FROM "+table.name()+" WHERE " + whereClause(values));
		ResultSet rs = ps.executeQuery();
		if(!rs.next())
		{
			closeConnection(connection, ps, rs);
			return null;
		}
		Field[] fields = clazz.getDeclaredFields();
		ArrayList<Object> result = new ArrayList<Object>();
		do{
			Object object = clazz.newInstance();
			for(Field field : fields)
				PropertyUtils.setProperty(object, field.getName(),rs.getObject(field.getName()));
			result.add(object);
		}while(rs.next());

		closeConnection(connection, ps, rs);
		return result;
	}


	protected String whereClause (HashMap<String, Object> values){
		String result ="";
		Set<String> columns  = values.keySet();
		for(String column : columns)
			result+=column+"="+parseType(values.get(column))+" AND ";
		return result.substring(0, result.length()-5);
	}


	private String parseType(Object value) {
		if(value instanceof Integer)
			return value.toString();
		if(value instanceof String)
			return "\'"+value+"\'";
		return value.toString();
	}
}
